import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:get/get.dart';
import 'package:ball_lion/entity/home/news_item_entity.dart';
import 'package:ball_lion/resources/colours.dart';
import 'package:ball_lion/routes/routes.dart';
import 'package:ball_lion/utils/utils.dart';
import 'package:ball_lion/utils/widget_utils.dart';
import 'package:ball_lion/widgets/base/wqs_dialog.dart';

import 'package:ball_lion/widgets/base/wqs_text.dart';

class NewsFloat2Widget extends StatefulWidget {
  const NewsFloat2Widget({super.key});

  static final List<NewsItemEntity> _news = [];
  static void Function()? _update;
  static Future<bool> addNews(NewsItemEntity? n) async {
    if (n == null) {
      return false;
    }
    final idx = _news.indexWhere((element) => element.id == n.id);
    if (idx >= 0 && idx < _news.length) {
      await Future.delayed(100.ms);
      await WidgetUtils.alertQuery("已存在于浮窗中");
      return false;
    }
    if (_news.length >= 5) {
      await Future.delayed(100.ms);
      // await Utils.alertQuery("浮窗数量已达最大，请清理后再添加");
      await Get.dialog(
          const QsDialog.single("当前浮窗已满，管理后可继续添加", confirmText: "我知道了"));
      // await showDialog(context: Get.context!, builder: (context) => CommonDialog.hint("浮窗数量已达最大，请清理后再添加"));
      return false;
    }

    _news.add(n);
    _update?.call();
    return true;
  }

  static bool existNews(int id) {
    final idx = _news.indexWhere((element) => element.id == id);
    if (idx >= 0 && idx < _news.length) {
      return true;
    }
    return false;
  }

  static delNews(int? id) {
    final idx = _news.indexWhere((element) => element.id == id);
    if (idx >= 0 && idx < _news.length) {
      _news.removeAt(idx);
      _update?.call();
    }
  }

  @override
  State<NewsFloat2Widget> createState() => _NewsFloat2WidgetState();
}

class _NewsFloat2WidgetState extends State<NewsFloat2Widget> {
  final double width = 58 + 8;
  bool expand = false;
  int? deleteI;

  late Offset _p = MediaQuery.of(context)
      .size
      .centerRight(Offset(-width, -MediaQuery.of(context).size.height / 6));
  Offset get p => _p;
  set p(Offset n) {
    double dx = n.dx;
    double dy = n.dy;
    if (dx > maxDx - 20) {
      dx = maxDx;
    } else if (dx < minDx + 20) {
      dx = minDx;
    }
    if (dy > maxDy) {
      dy = maxDy;
    } else if (dy < minDy) {
      dy = minDy;
    }
    _p = Offset(dx, dy);
  }

  late final maxDx = MediaQuery.of(context).size.width - width;
  late final maxDy = MediaQuery.of(context).size.height - width;
  late final double minDx = 8;
  late final minDy = MediaQuery.of(context).padding.top;
  Offset startPosition = Offset.zero;
  bool get atLeftEdge => p.dx == minDx;
  bool get atRightEdge => p.dx == maxDx;
  bool get atEdge => p.dx == maxDx || p.dx == 0;
  bool animateToEdge = false;

  List<NewsItemEntity> get news => NewsFloat2Widget._news;
  final _sc = StreamController.broadcast();

  @override
  void initState() {
    NewsFloat2Widget._update = () {
      expand = false;
      _sc.add(null);
    };
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: _sc.stream,
        builder: (context, snapshot) {
          if (news.isEmpty) {
            expand = false;
            return Positioned(child: Container());
          }
          return expand ? expandedWidget() : closedWidget();
        });
  }

  Widget closedWidget() {
    final child = GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        expand = true;
        update();
      },
      onPanStart: (details) {
        startPosition = p - details.localPosition;
      },
      onPanUpdate: (details) {
        animateToEdge = false;
        p = startPosition + details.localPosition;
        update();
      },
      onPanEnd: (details) {
        animateToEdge = true;
        update();
        Future.delayed(10.ms).then((value) {
          if (p.dx > MediaQuery.of(context).size.width / 2) {
            p = Offset(maxDx, p.dy);
          } else {
            p = Offset(minDx, p.dy);
          }
          update();
        });
      },
      child: Container(
          width: 58,
          height: 58,
          alignment: Alignment.center,
          decoration: BoxDecoration(
              color: Colors.white,
              boxShadow: const [
                BoxShadow(color: Colours.grey99, blurRadius: 2)
              ],
              borderRadius: BorderRadius.circular(8)),
          child: Stack(
            alignment: AlignmentDirectional.bottomEnd,
            children: [
              Image.asset(
                Utils.getImgPath('news_float_icon.png'),
                width: 28,
              ),
              Positioned(
                right: 7,
                bottom: 3,
                child: QsText('${news.length}',
                    fontSize: 11, fontWeight: FontWeight.w500),
              )
            ],
          ).animate(key: Key('${news.length}')).scale(
              duration: 300.ms,
              begin: const Offset(0.7, 0.7),
              end: const Offset(1, 1),
              curve: Curves.bounceOut)),
    );
    return animateToEdge
        ? AnimatedPositioned(
            left: p.dx,
            top: p.dy,
            duration: 100.ms,
            onEnd: () {
              animateToEdge = false;
              update();
            },
            child: child,
          )
        : Positioned(left: p.dx, top: p.dy, child: child);
  }

  Widget expandedWidget() {
    return Stack(
      children: [
        Positioned.fill(
            child: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTap: () {
            expand = false;
            update();
          },
          child: Container(
            color: Colors.white.withOpacity(0.2),
          ),
        )),
        Positioned(
            top: 320,
            right: 8,
            child: Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(8),
                boxShadow: [
                  BoxShadow(
                      color: Colours.grey66.withOpacity(0.5), blurRadius: 2)
                ],
              ),
              child: Column(
                  children: List.generate(
                      news.length, (i) => _expandedCell(news[i]))),
            ))
      ],
    );
  }

  Widget _expandedCell(NewsItemEntity e) {
    String title = '';
    if (e.type == 1) {
      title = e.title ?? '';
    } else {
      if (e.content.hasValue) {
        String content = e.content!.replaceAll(RegExp(r"\s+\n|\n\s"), "");
        title = '${content.characters.take(50)}';
      } else {
        title = '分享图片';
      }
    }
    final contentWidget = Container(
      width: 260,
      height: 60,
      padding: const EdgeInsets.only(left: 16),
      decoration: const BoxDecoration(
          border:
              Border(bottom: BorderSide(width: 0.5, color: Colours.greyEE))),
      child: Row(
        children: [
          Image.asset(
            Utils.getImgPath('float_article.png'),
            width: 20,
          ),
          const SizedBox(width: 12),
          Expanded(child: QsText(title, maxLines: 2, color: Colours.grey66)),
          Padding(
              padding: const EdgeInsets.all(12),
              child: Image.asset(
                Utils.getImgPath("close.png"),
                width: 14,
              )).tap(() {
            deleteI = e.id;
            update();
          }),
        ],
      ),
    ).tap(() {
      // news.removeWhere((element) => element.id == e.id);
      expand = false;
      if (e.imgStyle == 4) {
        Get.toNamed(Routes.homeVideoNews,
            arguments: e.id, parameters: {"classId": "${e.classId}"});
      } else {
        Get.toNamed(Routes.homenews,
            arguments: e.id, parameters: {"classId": "${e.classId}"});
      }
      update();
    });
    return deleteI != e.id
        ? contentWidget
        : contentWidget.animate(
            onComplete: (controller) {
              news.removeWhere((element) => element.id == deleteI);
              deleteI = null;
              update();
            },
          ).slide(
            duration: 200.ms, begin: Offset.zero, end: const Offset(1, 0));
  }
}
